package com.jing.cloud.client.zookeeper;

import com.google.common.collect.Maps;
import com.jing.cloud.client.factory.ClientPool;
import com.jing.cloud.service.Conf;
import com.jing.cloud.service.ServiceInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

public class ServiceTree {

    private static final Logger log = LoggerFactory.getLogger(ServiceTree.class);
    private static final String SPLIT_STR = "/";
    private CountDownLatch latch = new CountDownLatch(1);

    private final Node root = new Node();
    private final Map<String, ClientPool> clientMap = new ConcurrentHashMap<>();

    private ServiceTree() {
        init();
    }

    private static ServiceTree instance = new ServiceTree();

    public static ServiceTree getInstance() {
        return instance;
    }

    /**
     * 数据同步完成后调用
     *
     * @Description
     */
    public void countDown() {
        latch.countDown();
    }


    /**
     * 注册服务节点
     *
     * @param path zooKeeper节点路径
     * @param info zooKeeper节点数据
     * @Description
     */
    public void register(String path, ServiceInfo info) {
        log.info("register path:[{}] info:[{}]", path, info);
        String[] strs = path.split(SPLIT_STR);
        int len = strs.length;
        if (len < 3) {
            log.warn("invalid path [{}]", path);
            return;
        }
        if (!strs[1].equals(root.getKey())) {
            log.warn("invalid root [{}]", path);
            return;
        }
        Node node = root;
        // 以 2 级树 keyColumn 加锁
        synchronized (strs[2].intern()) {
            for (int i = 2; i < strs.length; i++) {
                String str = strs[i];
                Node currNode = node.getNodes().get(str);
                if (currNode == null) {
                    currNode = new Node();
                    currNode.setKey(str);
                    if (i == strs.length - 1 && info != null) {
                        currNode.setInfo(info);
                        currNode.setPath(path);
                        currNode.setVersion(info.getVersion());
                    }
                    node.getNodes().put(str, currNode);
                }
                node = currNode;
            }
        }
    }

    /**
     * 注销服务节点
     *
     * @param path 节点路径
     * @Description
     */
    public void unregister(String path) {
        log.info("register path:[{}]", path);
        String[] strs = path.split(SPLIT_STR);
        int len = strs.length;
        if (len < 4) {
            // 只对4级节点进行移除
            log.warn("invalid path [{}]", path);
            return;
        }
        if (!strs[1].equals(root.getKey())) {
            log.warn("invalid root [{}]", path);
            return;
        }
        Node node = root;
        // 以 2 级树 keyColumn 加锁
        synchronized (strs[2].intern()) {
            for (int i = 2; i < strs.length; i++) {
                String str = strs[i];
                Node currNode = node.getNodes().get(str);
                if (currNode != null) {
                    if (i == strs.length - 1) {
                        Node n = node.getNodes().get(str);
                        //当节点移除时，关闭连接池
                        closePool(n.getKey());
                        node.getNodes().remove(str);
                    }
                    node = currNode;
                } else {
                    return;
                }
            }
        }

    }


    public Map<String, Node> getNodes(String serviceName) {
        try {
            //等待同步完成
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Map<String, Node> nodeMap = Maps.newConcurrentMap();
        Node serviceTree = root.getNodes().get(serviceName);
        if (null == serviceTree) {
            log.error("service [{}] is not register yet");
        } else {
            nodeMap = serviceTree.getNodes();
        }
        return nodeMap;
    }

    private void init() {
        root.setKey(Conf.SERVICE_ROOT);
    }

    private void closePool(String key) {
        ClientPool pool = clientMap.get(key);
        clientMap.remove(key);
        if (pool != null) {
            try {
                pool.close();
            } catch (IOException e) {
                log.warn("close pool error key:[{}]", key, e);
            }
        }
    }


}
